/*
 * GPSServer.c
 *
 *  Created on: Feb 27, 2011
 *      Author: soapy
 */

#include "structs.h"
#include <stdio.h>	  /* for printf() and fprintf() */
#include <sys/socket.h>	  /* for socket(), connect(), send(), and recv() */
#include <sys/stat.h>
#include <arpa/inet.h>	  /* for sockaddr_in and inet_addr() */
#include <stdlib.h>	  /* supports all sorts of functionality */
#include <unistd.h>	  /* for close() */
#include <string.h>	  /* support any string ops */
#include <errno.h>

#include "GPSEncode.h"
#include "GPSFraming.h"
#include "structs.h"

#define MAX_SIZE 512
#define BUFF_SIZE 512

void friends(int u_id, location *location);
void history(int u_id, location *array, int *length);
int updateLoc(location l);
void HandleTCPClient(int);

const char *logDir = "./logs/";

int main (int argc, char *argv[])
{
    int *serverSocks;			/* Server Socket */
    int clientSock;                     /* Client Socket */

	if(argc < 3)
	{
		printf("Incorrect # of arguments, wanted:\n<timeout> <socket1> ...\n");
		exit(1);
	}
	
	long timeout = atol(argv[1]);
	int num_ports = argc-2;
	
	serverSocks = (int*)malloc(num_ports*sizeof(int));
	int maxDesc = -1;
	
	int i;
	for(i = 0; i<num_ports; i++)
	{
		serverSocks[i] = SetupTCPServerSocket(argv[i+2]);
		if(serverSocks[i] > maxDesc)
			maxDesc = serverSocks[i];
	}
	
	printf("Server starting\n");
	
	fd_set sockSet;
	
	while(1)
	{
		FD_ZERO(&sockSet); //zero out
		FD_SET(STDIN_FILENO, &sockSet); // add keyboard
		
		for(i = 0; i<num_ports; i++)
			FD_SET(serverSocks[i], &sockSet);
		
		struct timeval strTimeout;
		strTimeout.tv_sec = timeout;
		strTimeout.tv_usec = 0;

		if( select( maxDesc+1 , &sockSet, NULL, NULL, &strTimeout) == 0)
			printf("No responce in %ld secs, continuing\n", timeout);
		else
		{
			if(FD_ISSET(0, &sockSet))
			{
				puts("Shutting down server");
				break;
			}

			for(i = 0; i<num_ports; i++)
			{
				if(FD_ISSET(serverSocks[i], &sockSet))
				{
					printf("Request on port %d\n", i);
					clientSock = AcceptTCPConnection(serverSocks[i]);
					HandleTCPClient(clientSock);
				}
			}


		}

	}

	for( i =0 ; i<num_ports; i++)
		close(serverSocks[i]);
	return 0;
}




void HandleTCPClient(int clientSock)
{
			//Handle things
			//Create input stream from socket
			FILE *channel = fdopen(clientSock, "r+");
			if(channel == NULL)
			{
				printf("%d\n", errno);
				ExitWithMessage("fdopen() failure");
			}

			int message_size;
			uint8_t inBuffer[MAX_SIZE];
			uint8_t outBuffer[MAX_SIZE];
			header h;
			header newh;
			location l;

			size_t size;

			message_size = GetNextMsg(channel, inBuffer, MAX_SIZE);
				memset(&h, 0, sizeof(h));
				memset(&l, 0, sizeof(l));
				printf("Received %d bytes\n", message_size);

				memcpy(&h, inBuffer, sizeof(header));
				decode_header(&h);

				if(h.type == UPDATE)
				{
					memcpy(&l, inBuffer + sizeof(header), sizeof(location));
					decode_location(&l);
					if(updateLoc(l) != 0)
					{
						printf("updateLoc() failure");
					}
					init_header(&newh, UPDATE_ACK, 0);
					encode_header(&newh);
					memcpy(outBuffer, &newh, sizeof(header));
					
					message_size = sizeof(header);
					
					printf("Updated location of %d\n", l.u_id);
				}
				else if(h.type == FRIENDS_REQ)
				{
					uint32_t *id;
					location *locations;
					id = (uint32_t*)(inBuffer + sizeof(header));
					uint32_t length = h.length;
					locations = malloc(sizeof(location) * length);
					int i;
					for(i = 0; i < length; i++) //For each requested friend
					{
						id[i] = ntohl(id[i]);
						friends(id[i], &locations[i]);
					}
					
					init_header(&newh, FRIENDS_RESP, length);
					encode_header(&newh);
					memcpy(outBuffer, &newh, sizeof(header));
					memcpy(outBuffer+sizeof(header), locations, sizeof(location) * length);
					
					message_size = sizeof(header) + sizeof(location)*length;
					
					free(locations);
					
					printf("Recieved and handled request for %d friend locations\n", length);
				}
				else if(h.type == HISTORY_REQ)
				{
					uint32_t *id = (uint32_t*)(inBuffer + sizeof(header));
					
					*id = ntohl(*id);
					
					int length;
					location *array = malloc(sizeof(location)*10);
					history(*id, array, &length);
					
					init_header(&newh, HISTORY_RESP, length);
					encode_header(&newh);
					
					message_size = sizeof(header) + sizeof(location)*length;
					
					memcpy(outBuffer, &newh, sizeof(header));
					memcpy(outBuffer+sizeof(header), array, ( sizeof(location)*length > MAX_SIZE  ? MAX_SIZE : sizeof(location)*length  )   );

					if(length > 0)
						free(array);
					
					printf("Recieved request for history of %d.  Send %d locations\n", *id, length);
				}
			

			if(PutMsg(outBuffer, message_size, channel) < 0)
			{
				fputs("Error framing/outputting message\n", stderr);
			}

			//TODO announce we handled stuff

			fflush(channel);

			puts("Client finished");


			close(clientSock);
}

int updateLoc(location l)
{
	FILE *file;
	char space[512];
	char file_name[512];

	strcpy(file_name, logDir);
	snprintf(space, 512, "%d", l.u_id);
	strcat(file_name, space);

	file = fopen(file_name, "a+");
	if(file == NULL)
	{
		return -1;
	}
	fprintf(file, "(");

	snprintf(space, 512, "%f", (float)l.latitude);
	strcat(space, ",");
	fprintf(file, space);

	snprintf(space, 512, "%f", (float)l.longitude);
	strcat(space, ",");
	fprintf(file, space);

	snprintf(space, 512, "%f", (float)l.altitude);
	strcat(space, ")");
	fprintf(file, space);

	fclose(file);
	return 0;
}

void friends(int u_id, location *location)
{
	FILE *file;
	char space[512];
	char file_name[512];
	
	char *file_cont;
	int offset;
	int end;
	
	strcpy(file_name, logDir);
	snprintf(space, 512, "%d", u_id);
	strcat(file_name, space);

	file = fopen(file_name, "r");
	if(file == NULL)
	{
		printf("Warning: could not find user %d\n", u_id);
		return;
	}
	
	struct stat fstats;
	stat(file_name, &fstats);
	
	int total_size = fstats.st_size;
	offset = total_size-1;
	file_cont = malloc(total_size);
	
	fread(file_cont, 1, total_size, file);
	
	while(file_cont[offset] != ')') offset--;
	end = offset;
	while(file_cont[offset] != ',') offset --;
	//now offset is start of float and end is end of float
	memcpy(space, &file_cont[offset+1], end-(offset+1));

	location->altitude = atof(space);

	end = offset+1; offset--;
	while(file_cont[offset] != ',') offset --;
	//now offset is start of float and end is end of float
	memcpy(space, &file_cont[offset+1], end-(offset+1));

	location->longitude = atof(space);
	
	end = offset+1;
	while(file_cont[offset] != '(') offset --;
	//now offset is start of float and end is end of float
	memcpy(space, &file_cont[offset+1], end-(offset+1));
	
	location->latitude = atof(space);
	
	location->u_id = u_id;
	
	encode_location(location);
}

void history(int u_id, location *array, int *length)
{
	FILE *file;
	char space[512];
	char file_name[512];
	
	char *file_cont;
	int offset;
	int start=0;
	
	//create filename
	strcpy(file_name, logDir);
	snprintf(space, 512, "%d", u_id);
	strcat(file_name, space);

	//open file
	file = fopen(file_name, "r");
	if(file == NULL)
	{
		printf("Warning: could not find user %d\n", u_id);
		*length = 0;
		return;
	}
	
	printf("u_id: %d\n", u_id);
	
	//size stuff
	struct stat fstats;
	stat(file_name, &fstats);
	int total_size = fstats.st_size;
	
	file_cont = malloc(total_size*sizeof(char));
	fread(file_cont, 1, total_size, file);
	
	offset = 0;
	int i =0;
	
	for(i=0;   file_cont[offset] != '\0' && file_cont[offset+1] != '\0' && i < 10; i++)
	{
		location *location = &array[i];
		
		while(file_cont[offset] != '(')	offset++;
			
		start = offset+1;
		while(file_cont[offset] != ',') offset ++;
		//now offset is start of float and end is end of float
		memcpy(space, &file_cont[start], offset-(start+1));
	
		location->latitude = atof(space);
	printf("%f\n",atof(space));
		start = offset+1; offset++;
		while(file_cont[offset] != ',') offset ++;
		//now offset is start of float and end is end of float
		memcpy(space, &file_cont[start], offset-(start+1));
	
		location->longitude = atof(space);
		
		start = offset+1;
		while(file_cont[offset] != ')') offset ++;
		//now offset is start of float and end is end of float
		memcpy(space, &file_cont[start], offset-(start+1));
		
		location->altitude = atof(space);
		
		location->u_id = u_id;
	
		encode_location(location);
	}

	*length = i;
	
}

int test(char *array, int len, int pointer)
{
	if( pointer >= len || pointer<0)
		return 0;
	if(array[pointer] == '\0')
		return 0;
	return 1;
}
